-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[lldb] Clear thread-creation breakpoints in ProcessGDBRemote::Clear #134397
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[lldb] Clear thread-creation breakpoints in ProcessGDBRemote::Clear #134397
Conversation
Currently, these breakpoints are being accumulated every time a new process if created (e.g. through a `run`). Depending on the circumstances, the old breakpoints are even left enabled, interfering with subsequent processes. This is addressed by removing the breakpoints in ProcessGDBRemote::Clear Note that these breakpoints are more of a PlatformDarwin thing, so in the future we should look into moving them there.
a1e12d0
to
e7689b6
Compare
@llvm/pr-subscribers-lldb Author: Felipe de Azevedo Piovezan (felipepiovezan) ChangesCurrently, these breakpoints are being accumulated every time a new process if created (e.g. through a Note that these breakpoints are more of a PlatformDarwin thing, so in the future we should look into moving them there. Full diff: https://github.com/llvm/llvm-project/pull/134397.diff 2 Files Affected:
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 68360788c96e6..d7e8c2ce7944e 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -3410,6 +3410,9 @@ Status ProcessGDBRemote::DisableWatchpoint(WatchpointSP wp_sp, bool notify) {
void ProcessGDBRemote::Clear() {
m_thread_list_real.Clear();
m_thread_list.Clear();
+ if (m_thread_create_bp_sp)
+ if (TargetSP target_sp = m_target_wp.lock())
+ target_sp->RemoveBreakpointByID(m_thread_create_bp_sp->GetID());
}
Status ProcessGDBRemote::DoSignal(int signo) {
diff --git a/lldb/test/API/macosx/thread_start_bps/TestBreakpointsThreadInit.py b/lldb/test/API/macosx/thread_start_bps/TestBreakpointsThreadInit.py
index 1c6fd4f91c73e..bf667f6f7d336 100644
--- a/lldb/test/API/macosx/thread_start_bps/TestBreakpointsThreadInit.py
+++ b/lldb/test/API/macosx/thread_start_bps/TestBreakpointsThreadInit.py
@@ -35,3 +35,23 @@ def test_internal_bps_resolved(self):
for bp in bps:
num_resolved += bp.GetNumResolvedLocations()
self.assertGreater(num_resolved, 0)
+
+ @skipUnlessDarwin
+ def test_internal_bps_deleted_on_relaunch(self):
+ self.build()
+
+ source_file = lldb.SBFileSpec("main.c")
+ target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
+ self, "initial hello", source_file
+ )
+
+ self.runCmd("break list --internal")
+ output = self.res.GetOutput()
+ self.assertEqual(output.count("thread-creation"), 1)
+
+ process.Kill()
+ self.runCmd("run", RUN_SUCCEEDED)
+
+ self.runCmd("break list --internal")
+ output = self.res.GetOutput()
+ self.assertEqual(output.count("thread-creation"), 1)
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree these don't belong in ProcessGDBRemote, but this is a small and obvious change so it's fine to fix the status quo for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 on what Jim said.
…lvm#134397) Currently, these breakpoints are being accumulated every time a new process if created (e.g. through a `run`). Depending on the circumstances, the old breakpoints are even left enabled, interfering with subsequent processes. This is addressed by removing the breakpoints in ProcessGDBRemote::Clear Note that these breakpoints are more of a PlatformDarwin thing, so in the future we should look into moving them there. (cherry picked from commit 232525f)
…lvm#134397) Currently, these breakpoints are being accumulated every time a new process if created (e.g. through a `run`). Depending on the circumstances, the old breakpoints are even left enabled, interfering with subsequent processes. This is addressed by removing the breakpoints in ProcessGDBRemote::Clear Note that these breakpoints are more of a PlatformDarwin thing, so in the future we should look into moving them there. (cherry picked from commit 232525f) (cherry picked from commit 8afffeb)
…:Clear (llvm#134397)" This reapplies commit 232525f. The original commit triggered a sanitizer failure when Target was destroyed. In Target::Destroy, `DeleteCurrentProcess` was called, but it did not destroy the thread creation breakpoints for the underlying ProcessGDBRemote, because said method would not call `ProcessGDBRemote::Clear`. Target then proceeded to destroy its breakpoints, which resulted in a call to the destructor a std::vector containing the breakpoints. Through a sequence of complicated events, destroying breakpoints caused the reference count of the underlying to finally reach zero. This, in turn, called `ProcessGDBRemote::Clear`, which attempted to destroy the breakpoints. To do that, it would query back into the Target vector of breakpoint, which we are in the middle of destroying. We solve this by moving the breakpoint deletion into `Process:DoDestroy`, which is a virtual Process method that will be called much earlier.
…:Clear (llvm#134397)" This reapplies commit 232525f. The original commit triggered a sanitizer failure when Target was destroyed. In Target::Destroy, `DeleteCurrentProcess` was called, but it did not destroy the thread creation breakpoints for the underlying ProcessGDBRemote, because said method would not call `ProcessGDBRemote::Clear`. Target then proceeded to destroy its breakpoints, which resulted in a call to the destructor a std::vector containing the breakpoints. Through a sequence of complicated events, destroying breakpoints caused the reference count of the underlying to finally reach zero. This, in turn, called `ProcessGDBRemote::Clear`, which attempted to destroy the breakpoints. To do that, it would query back into the Target vector of breakpoint, which we are in the middle of destroying. We solve this by moving the breakpoint deletion into `Process:DoDestroy`, which is a virtual Process method that will be called much earlier.
…:Clear (llvm#134397)" This reapplies commit 232525f. The original commit triggered a sanitizer failure when `Target` was destroyed. In `Target::Destroy`, `DeleteCurrentProcess` was called, but it did not destroy the thread creation breakpoints for the underlying `ProcessGDBRemote` because `ProcessGDBRemote::Clear` was not called in that path. `Target `then proceeded to destroy its breakpoints, which resulted in a call to the destructor of a `std::vector` containing the breakpoints. Through a sequence of complicated events, destroying breakpoints caused the reference count of the underlying `ProcessGDBRemote` to finally reach zero. This, in turn, called `ProcessGDBRemote::Clear`, which attempted to destroy the breakpoints. To do that, it would go back into the Target's vector of breakpoints, which we are in the middle of destroying. We solve this by moving the breakpoint deletion into `Process:DoDestroy`, which is a virtual Process method that will be called much earlier.
…:Clear (#134397)" (#135296) This reapplies commit 232525f. The original commit triggered a sanitizer failure when `Target` was destroyed. In `Target::Destroy`, `DeleteCurrentProcess` was called, but it did not destroy the thread creation breakpoints for the underlying `ProcessGDBRemote` because `ProcessGDBRemote::Clear` was not called in that path. `Target `then proceeded to destroy its breakpoints, which resulted in a call to the destructor of a `std::vector` containing the breakpoints. Through a sequence of complicated events, destroying breakpoints caused the reference count of the underlying `ProcessGDBRemote` to finally reach zero. This, in turn, called `ProcessGDBRemote::Clear`, which attempted to destroy the breakpoints. To do that, it would go back into the Target's vector of breakpoints, which we are in the middle of destroying. We solve this by moving the breakpoint deletion into `Process:DoDestroy`, which is a virtual Process method that will be called much earlier.
…:Clear (llvm#134397)" This reverts commit 232525f.
…:Clear (llvm#134397)" (llvm#135296) This reapplies commit llvm@232525f. The original commit triggered a sanitizer failure when `Target` was destroyed. In `Target::Destroy`, `DeleteCurrentProcess` was called, but it did not destroy the thread creation breakpoints for the underlying `ProcessGDBRemote` because `ProcessGDBRemote::Clear` was not called in that path. `Target `then proceeded to destroy its breakpoints, which resulted in a call to the destructor of a `std::vector` containing the breakpoints. Through a sequence of complicated events, destroying breakpoints caused the reference count of the underlying `ProcessGDBRemote` to finally reach zero. This, in turn, called `ProcessGDBRemote::Clear`, which attempted to destroy the breakpoints. To do that, it would go back into the Target's vector of breakpoints, which we are in the middle of destroying. We solve this by moving the breakpoint deletion into `Process:DoDestroy`, which is a virtual Process method that will be called much earlier. (cherry picked from commit c2939b9)
…tiondeletion_62 Reland "[lldb] Clear thread-creation breakpoints in ProcessGDBRemote::Clear (llvm#134397)"
…:Clear (llvm#134397)" This reverts commit 232525f. This change is causing test crashes while running TestCompletion.py on Darwin systems, most of the CI runs have failed since it has been merged in.
…:Clear (llvm#134397)" (llvm#135296) This reapplies commit llvm@232525f. The original commit triggered a sanitizer failure when `Target` was destroyed. In `Target::Destroy`, `DeleteCurrentProcess` was called, but it did not destroy the thread creation breakpoints for the underlying `ProcessGDBRemote` because `ProcessGDBRemote::Clear` was not called in that path. `Target `then proceeded to destroy its breakpoints, which resulted in a call to the destructor of a `std::vector` containing the breakpoints. Through a sequence of complicated events, destroying breakpoints caused the reference count of the underlying `ProcessGDBRemote` to finally reach zero. This, in turn, called `ProcessGDBRemote::Clear`, which attempted to destroy the breakpoints. To do that, it would go back into the Target's vector of breakpoints, which we are in the middle of destroying. We solve this by moving the breakpoint deletion into `Process:DoDestroy`, which is a virtual Process method that will be called much earlier.
Currently, these breakpoints are being accumulated every time a new process if created (e.g. through a
run
). Depending on the circumstances, the old breakpoints are even left enabled, interfering with subsequent processes. This is addressed by removing the breakpoints in ProcessGDBRemote::ClearNote that these breakpoints are more of a PlatformDarwin thing, so in the future we should look into moving them there.